package com.own.component.common.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.own.component.common.base.entity.BaseBo;
import com.own.component.common.base.entity.BaseMap;
import com.own.component.common.base.entity.BaseQuery;
import com.own.component.common.base.entity.po.BaseBean;
import com.own.component.common.base.entity.vo.BaseBeanVo;
import com.own.component.common.base.mapper.BasePageMapper;
import com.own.component.common.base.service.BaseBindTwoService;
import com.own.component.common.em.BusinessEnum;
import com.own.component.common.exception.BusinessException;
import com.own.component.common.model.UpdateModel;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * AbstractBaseBindTwoService
 * 将绑定操作简化（流程简化。执行简化）
 *
 * @author chenxueli.0
 * @date 2020/12/24 19:05
 * @since 3.2.1
 */
@Service
public abstract class AbstractBaseBindTwoService<
        PO extends BaseBean,
        BO extends BaseBo<PO>,
        VO extends BaseBeanVo<PO>,
        MAP extends BaseMap<PO>,
        QUERY extends BaseQuery,
        MAPPER extends BasePageMapper<PO, VO, MAP, QUERY>
        > extends AbstractBaseService<PO, BO, VO, MAP, QUERY, MAPPER>
        implements BaseBindTwoService<PO, BO, VO, MAP, QUERY> {

    @Autowired
    @SuppressWarnings("all")
    private MAPPER mapper;

    /**
     * 获取绑定的数据
     *
     * @param pk 绑定的主id
     * @return 绑定标识
     */
    @Override
    public List<PO> listBindPoByPk(@NonNull Long pk) {
        var wrapper = new QueryWrapper<PO>().lambda().eq(getPkExtractor(), pk);
        return mapper.selectList(wrapper);
    }

    /**
     * 获取绑定的数据
     *
     * @param fk 绑定的副id
     * @return 绑定标识
     */
    @Override
    public List<PO> listBindPoByFk(@NonNull Long fk) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getFkExtractor(), fk);
        return mapper.selectList(wrapper);
    }

    /**
     * 获取绑定的数据
     *
     * @param pk     绑定的主id
     * @param bindId 绑定的id
     * @return 绑定标识
     */
    @Override
    public PO getBindPo(@NonNull Long pk, @NonNull Long bindId) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getPkExtractor(), pk)
                .eq(getFkExtractor(), bindId);
        return mapper.selectOne(wrapper);
    }

    /**
     * 验证绑定的数据
     *
     * @param pk     绑定的主id
     * @param bindId 绑定的id
     */
    @Override
    public void checkBindPo(@NonNull Long pk, @NonNull Long bindId) {
        var po = getBindPo(pk, bindId);
        if (po == null) {
            throw new BusinessException(BusinessEnum.NO_BIND_DATA);
        }
    }

    /**
     * 单个数据绑定
     *
     * @param pk     绑定的主id
     * @param bindId 绑定的id
     * @return 绑定标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> bind(@NonNull Long pk, @NonNull Long bindId) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getPkExtractor(), pk)
                .eq(getFkExtractor(), bindId);
        if (mapper.selectCount(wrapper) > 0) {
            throw new BusinessException(BusinessEnum.ALREADY_BIND_DATA);
        }
        mapper.insert(buildPo(pk, bindId));
        return new UpdateModel<>(true);
    }

    /**
     * 批量数据绑定
     *
     * @param pk         绑定的主id
     * @param bindIdList 绑定的id列表
     * @return 绑定标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> bindBatch(@NonNull Long pk, @NonNull List<Long> bindIdList) {
        // 查询出已经绑定的列表
        var wrapper = new QueryWrapper<PO>().lambda().eq(getPkExtractor(), pk);
        var list = mapper.selectList(wrapper);
        // 筛选出可以添加的列表
        list.parallelStream().map(getFkExtractor()).forEach(bindIdList::remove);
        // 如果只有1条数据，执行单个绑定业务
        if (bindIdList.size() == 1) {
            return bind(pk, bindIdList.get(0));
        }
        // 如果没有数据抛出异常
        if (bindIdList.size() == 0) {
            throw new BusinessException(BusinessEnum.NO_BIND_DATA);
        }
        // 执行批量添加
        var addList = bindIdList.parallelStream().map(item -> buildPo(pk, item)).collect(Collectors.toList());
        return new UpdateModel<>(mapper.insertBatch(addList) == addList.size());
    }

    /**
     * 批量数据绑定
     *
     * @param pkList 绑定的主id列表
     * @param bindId 绑定的id
     * @return 绑定标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> bindBatch(@NonNull List<Long> pkList, @NonNull Long bindId) {
        // 查询出已经绑定的列表
        var wrapper = new QueryWrapper<PO>().lambda().eq(getFkExtractor(), bindId);
        var list = mapper.selectList(wrapper);
        // 筛选出可以添加的列表
        list.parallelStream().map(getPkExtractor()).forEach(pkList::remove);
        // 如果只有1条数据，执行单个绑定业务
        if (pkList.size() == 1) {
            return bind(pkList.get(0), bindId);
        }
        // 如果没有数据抛出异常
        if (pkList.size() == 0) {
            throw new BusinessException(BusinessEnum.NO_BIND_DATA);
        }
        // 执行批量添加
        var addList = pkList.parallelStream().map(item -> buildPo(item, bindId)).toList();
        return new UpdateModel<>(mapper.insertBatch(addList) == addList.size());
    }

    /**
     * 单个数据解绑
     *
     * @param pk       解绑的主id
     * @param unbindId 解绑的id
     * @return 解绑标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> unbind(@NonNull Long pk, @NonNull Long unbindId) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getPkExtractor(), pk)
                .eq(getFkExtractor(), unbindId);
        if (mapper.selectCount(wrapper) == 0) {
            throw new BusinessException(BusinessEnum.ALREADY_UNBIND_DATA);
        }
        mapper.delete(wrapper);
        return new UpdateModel<>(true);
    }

    /**
     * 批量数据解绑
     *
     * @param pk           解绑的主id
     * @param unbindIdList 解绑的id列表
     * @return 解绑标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> unbindBatch(@NonNull Long pk, @NonNull List<Long> unbindIdList) {
        // 查询出已经绑定的列表
        var wrapper = new QueryWrapper<PO>().lambda().eq(getPkExtractor(), pk);
        var list = mapper.selectList(wrapper);
        // 筛选出需要删除的列表
        var deleteList = list.parallelStream()
                .map(getFkExtractor())
                .filter(unbindIdList::contains)
                .toList();
        // 如果只有1条数据，执行单个解绑业务
        if (deleteList.size() == 1) {
            return unbind(pk, deleteList.get(0));
        }
        // 如果没有数据，抛出异常
        if (deleteList.size() == 0) {
            throw new BusinessException(BusinessEnum.NO_UNBIND_DATA);
        }
        // 执行批量删除
        wrapper.in(getPkExtractor(), deleteList);
        mapper.delete(wrapper);
        return new UpdateModel<>(true);
    }

    /**
     * 根据主id修改绑定关系
     *
     * @param pk1 原id
     * @param pk2 现id
     * @return 修改标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> changeBindByPk(@NonNull Long pk1, @NonNull Long pk2) {
        // 查询原来的所有数据
        var list = listBindPoByPk(pk1);
        // 获取删除的id列表
        var deleteIdList = list.stream().map(PO::getId).collect(Collectors.toList());
        if (deleteIdList.size() > 0) {
            // 删除原来的数据
            mapper.deleteBatchIds(deleteIdList);
        }
        // 构造新的数据列表
        var newFkList = list.stream().map(getFkExtractor()).toList();
        if (newFkList.size() > 0) {
            // 执行添加新数据
            return bindBatch(pk2, newFkList);
        }
        return new UpdateModel<>(true);
    }

    /**
     * 根据副id修改绑定关系
     *
     * @param fk1 原id
     * @param fk2 现id
     * @return 修改标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> changeBindByFk(@NonNull Long fk1, @NonNull Long fk2) {
        // 查询原来的所有数据
        var list = listBindPoByFk(fk1);
        // 获取删除的id列表
        var deleteIdList = list.stream().map(PO::getId).collect(Collectors.toList());
        if (deleteIdList.size() > 0) {
            // 删除原来的数据
            mapper.deleteBatchIds(deleteIdList);
        }
        // 构造新的数据列表
        var newPkList = list.stream().map(getPkExtractor()).toList();
        if (newPkList.size() > 0) {
            // 执行添加新数据
            return bindBatch(newPkList, fk2);
        }
        return new UpdateModel<>(true);
    }

    /**
     * 根据主id删除数据
     *
     * @param pk 主id
     * @return 修改标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> deleteByPk(@NonNull Long pk) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getPkExtractor(), pk);
        mapper.delete(wrapper);
        return new UpdateModel<>(true);
    }

    /**
     * 根据副id删除数据
     *
     * @param fk 副id
     * @return 修改标识
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateModel<Boolean> deleteByFk(@NonNull Long fk) {
        var wrapper = new QueryWrapper<PO>().lambda()
                .eq(getFkExtractor(), fk);
        mapper.delete(wrapper);
        return new UpdateModel<>(true);
    }

}
